//
// Created by Particle_G on 2020/2/24.
//

#ifndef HDUSTEA_PLUGIN_HDUSTEA_HPP
#define HDUSTEA_PLUGIN_HDUSTEA_HPP

#define AUTH_MASTER 100
#define AUTH_DEVELOPER 90
#define AUTH_OWNER 80
#define AUTH_MANAGER 70

#define MAX_BAN_TIME 2592000
#define DEVELOPER_ACCOUNT 1135989508
#define HUOHUO_ACCOUNT 1204089960
#define MAIN_GROUP 628669530

#include <iostream>
#include <sstream>
#include <regex>
#include <random>
#include <vector>
#include <set>
#include <thread>

#include <cstdint>

#include <bsoncxx/json.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/document/element.hpp>
#include <bsoncxx/exception/exception.hpp>

#include <mongocxx/exception/bulk_write_exception.hpp>
#include <mongocxx/exception/error_code.hpp>
#include <mongocxx/exception/logic_error.hpp>
#include <mongocxx/exception/operation_exception.hpp>
#include <mongocxx/exception/server_error_code.hpp>

#include <mongocxx/instance.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>

#endif //HDUSTEA_PLUGIN_HDUSTEA_HPP

using namespace cq;
using namespace std;
using Message = cq::message::Message;
using MessageSegment = cq::message::MessageSegment;

using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::document;

const vector<string> GROUP_AVAILABLE_COMMANDS = {"#h", "#ban", "#unban"};
const vector<string> SINGLE_AVAILABLE_COMMANDS = {"#h", "#reboot"};

regex regexHelp(R"([#＃][h?])");
regex regexBan(R"([#＃]ban.*)");
regex regexUnban(R"([#＃]ban.*)");

regex regexMongoAdd(R"([#＃]db add)");
regex regexMongoDelete(R"([#＃]db delete)");
regex regexMongoEdit(R"([#＃]db edit)");
regex regexMongoSearch(R"([#＃]db search)");

namespace hdustea {

    namespace group {
        int CommandCheck(const string &command_str, const vector<string> &availableCommands_vec);

        int32_t GetUserAuthLevel(const string &groupID_str, int64_t userID_int, const mongocxx::database &tempDatabase);

        template<typename T>
        void GetUserData(int64_t userID_int, const string &dataKey, T &dataType, mongocxx::collection tempCollection);

        int CommandCheck(const string &command_str, const vector<string> &availableCommands_vec) {
            for (unsigned int i = 0; i < availableCommands_vec.size(); ++i) {
                if (command_str == availableCommands_vec[i]) {
                    return i;
                }
            }
            return -1;
        }

        int32_t
        GetUserAuthLevel(const string &groupID_str, int64_t userID_int, const mongocxx::database &tempDatabase) {
            int32_t authLevel = 0;
            try {
                GetUserData(userID_int, "authLevel", authLevel, tempDatabase.collection(groupID_str));

            } catch (string &) {
                authLevel = -1;
            }
            return authLevel;
        }

        template<typename T>
        void GetUserData(int64_t userID_int, const string &dataKey, T &dataType, mongocxx::collection tempCollection) {
            bsoncxx::stdx::optional<bsoncxx::document::value> userObject = tempCollection.find_one(
                    document{} << "userID" << userID_int << finalize);
            if (userObject) {
                if (typeid(dataType) == typeid(int32_t)) {
                    dataType = userObject->view()[dataKey].get_int32().value;
                } else if (typeid(dataType) == typeid(int64_t)) {
                    dataType = userObject->view()[dataKey].get_int64().value;
                } else if (typeid(dataType) == typeid(double)) {
                    dataType = userObject->view()[dataKey].get_double().value;
                } else if (typeid(dataType) == typeid(string)) {
                    stringstream tempSS;
                    tempSS << userObject->view()[dataKey].get_utf8().value;
                    tempSS >> dataType;
                } else if (typeid(dataType) == typeid(bool)) {
                    dataType = userObject->view()[dataKey].get_int32().value;
                }
            } else {
                string e = "KEY_NOT_FOUND";
                throw e;
            }
        }

        namespace manage {
            void CommandHelp(int64_t groupID_int, unsigned int paramCounts_int);

            void CommandBan(int64_t groupID_int, int64_t callerID_int, const vector<string> &paramList, int32_t authLevel_int,
                            const mongocxx::database &tempDatabase);

            void CommandUnban(int64_t groupID_int, int64_t callerID_int, const vector<string> &paramList, int32_t authLevel_int,
                              const mongocxx::database &tempDatabase);

            void CommandHelp(int64_t groupID_int, unsigned int paramCounts_int) {
                if (paramCounts_int != 1) {
                    try {
                        send_group_message(groupID_int, "参数个数错误！应为: 0 个");
                    } catch (ApiError &e) {
                        logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                    }
                } else {
                    string responseMessage = "HDUSTEA插件指令列表\n"
                                             "  #ban [xxx] [@xxx]\n"
                                             "  #unban {@xxx}\n"
                                             "输入指令 + \"-h\" 来获取对应指令的帮助";
                    try {
                        send_group_message(groupID_int, responseMessage);
                    } catch (ApiError &e) {
                        logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                    }
                }
            }

            void CommandBan(int64_t groupID_int, int64_t callerID_int, const vector<string> &paramList, int32_t authLevel_int,
                            const mongocxx::database &tempDatabase) {
                smatch subMatches;
                switch (paramList.size()) {
                    case 1:
                        try {
                            random_device rd;
                            mt19937 gen(rd());
                            lognormal_distribution<> d(1, 1);
                            int banTime_int = int(round(d(gen) * 300.0));
                            set_group_ban(groupID_int, HUOHUO_ACCOUNT, banTime_int);
                            send_group_message(groupID_int, "[CQ:at,qq=" + to_string(HUOHUO_ACCOUNT) + "] 被禁言 " +
                                                            to_string(banTime_int) + " 秒");
                        } catch (ApiError &e) {
                            logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                        }
                        break;
                    case 2:
                        if (paramList[1] == "-h") {
                            string responseMessage = "#ban指令帮助：\n"
                                                     "  [xxx] 设置禁言时长，留空默认服从(1,1)偏方正态分布\n"
                                                     "  [@xxx] 指定被执行成员，留空默认为或或";
                            try {
                                send_group_message(groupID_int, responseMessage);
                            } catch (ApiError &e) {
                                logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                            }
                        } else if (regex_match(paramList[1], subMatches, regex(R"((\d{1,7}))"))) {
                            int32_t banTime_int = strtol(subMatches[1].str().c_str(), nullptr, 10);
                            if (banTime_int > MAX_BAN_TIME) {
                                try {
                                    send_group_message(groupID_int, "参数错误：第 1 个参数类型或范围错误");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            } else {
                                try {
                                    set_group_ban(groupID_int, HUOHUO_ACCOUNT, banTime_int);
                                    send_group_message(groupID_int, "[CQ:at,qq=" + to_string(HUOHUO_ACCOUNT) + "] 被禁言 " +
                                                                    to_string(banTime_int) + " 秒");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            }
                        } else if (regex_match(paramList[1], subMatches, regex(R"(\[CQ:at,qq=(\d{5,20})\]\s*)"))) {
                            int64_t userID_int = strtol(subMatches[1].str().c_str(), nullptr, 10);
                            int32_t tempAuthLevel_int = hdustea::group::GetUserAuthLevel(to_string(groupID_int),
                                                                                         userID_int, tempDatabase);
                            if (authLevel_int > tempAuthLevel_int) {
                                try {
                                    random_device rd;
                                    mt19937 gen(rd());
                                    lognormal_distribution<> d(1, 1);
                                    int banTime_int = int(round(d(gen) * 300.0));
                                    set_group_ban(groupID_int, userID_int, banTime_int);
                                    send_group_message(groupID_int, "[CQ:at,qq=" + to_string(userID_int) + "] 被禁言 " +
                                                                    to_string(banTime_int) + " 秒");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            } else {
                                try {
                                    send_group_message(groupID_int, "权限错误：无法禁言高于或等于自己权限的成员");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            }
                        } else {
                            try {
                                send_group_message(groupID_int, "参数错误：第 1 个参数无法被识别");
                            } catch (ApiError &e) {
                                logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                            }
                        }
                        break;
                    case 3:
                        if (paramList[1] == "-h") {
                            try {
                                send_group_message(groupID_int, "参数错误：多余的第 2 个参数");
                            } catch (ApiError &e) {
                                logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                            }
                        } else if (regex_match(paramList[1], subMatches, regex(R"((\d{1,7}))"))) {
                            int32_t banTime_int = strtol(subMatches[1].str().c_str(), nullptr, 10);
                            if (banTime_int > MAX_BAN_TIME) {
                                try {
                                    send_group_message(groupID_int, "参数错误：第 1 个参数类型或范围错误");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            } else {
                                if (regex_match(paramList[2], subMatches, regex(R"(\[CQ:at,qq=(\d{5,20})\]\s*)"))) {
                                    int64_t userID_int = strtol(subMatches[1].str().c_str(), nullptr, 10);
                                    int32_t tempAuthLevel_int = hdustea::group::GetUserAuthLevel(to_string(groupID_int),
                                                                                                 userID_int, tempDatabase);
                                    if (authLevel_int > tempAuthLevel_int) {
                                        try {
                                            set_group_ban(groupID_int, userID_int, banTime_int);
                                            send_group_message(groupID_int, "[CQ:at,qq=" + to_string(userID_int) + "] 被禁言 " +
                                                                            to_string(banTime_int) + " 秒");
                                        } catch (ApiError &e) {
                                            logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                        }
                                    } else {
                                        try {
                                            send_group_message(groupID_int, "权限错误：无法禁言高于或等于自己权限的成员");
                                        } catch (ApiError &e) {
                                            logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                        }
                                    }
                                } else {
                                    try {
                                        send_group_message(groupID_int, "参数错误：第 2 个参数类型或范围错误");
                                    } catch (ApiError &e) {
                                        logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                    }
                                }
                            }
                        } else {
                            try {
                                send_group_message(groupID_int, "参数错误：第 1 个参数无法被识别");
                            } catch (ApiError &e) {
                                logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                            }
                        }
                        break;
                    default:
                        try {
                            send_group_message(groupID_int, "参数错误：参数个数 \"" + to_string(paramList.size() - 1) + "\" 错误，应为 [0-2]");
                        } catch (ApiError &e) {
                            logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                        }
                        break;
                }
            }

            void CommandUnban(int64_t groupID_int, int64_t callerID_int, const vector<string> &paramList, int32_t authLevel_int,
                              const mongocxx::database &tempDatabase) {
                smatch subMatches;
                switch (paramList.size()) {
                    case 2:
                        if (paramList[1] == "-h") {
                            string responseMessage = "#unban指令帮助：\n"
                                                     "  {@xxx} 指定被执行成员";
                            try {
                                send_group_message(groupID_int, responseMessage);
                            } catch (ApiError &e) {
                                logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                            }
                        } else if (regex_match(paramList[1], subMatches, regex(R"(\[CQ:at,qq=(\d{5,20})\]\s*)"))) {
                            int64_t userID_int = strtol(subMatches[1].str().c_str(), nullptr, 10);
                            int32_t tempAuthLevel_int = hdustea::group::GetUserAuthLevel(to_string(groupID_int),
                                                                                         userID_int, tempDatabase);
                            if (authLevel_int > tempAuthLevel_int) {
                                try {
                                    set_group_ban(groupID_int, userID_int, 0);
                                    send_group_message(groupID_int, "[CQ:at,qq=" + to_string(userID_int) + "] 被解除禁言");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            } else {
                                try {
                                    send_group_message(groupID_int, "权限错误：无法解禁高于或等于自己权限的成员");
                                } catch (ApiError &e) {
                                    logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                                }
                            }
                        } else {
                            try {
                                send_group_message(groupID_int, "参数错误：第 1 个参数无法被识别");
                            } catch (ApiError &e) {
                                logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                            }
                        }
                        break;
                    default:
                        try {
                            send_group_message(groupID_int, "参数错误：参数个数 \"" + to_string(paramList.size() - 1) + "\" 错误，应为 1");
                        } catch (ApiError &e) {
                            logging::warning("群聊", "群聊消息发送失败, 错误码: " + to_string(e.code));
                        }
                        break;
                }
            }
        }
        namespace discuss {

        }
        namespace file {

        }


    }
    namespace single {
        namespace manage {
        }
    }
}